﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Xml;

namespace PicBagDownloader
{
    public partial class Form1 : Form
    {
        string DownloadPath = Config.Default.DownPath;
        public DataTable dt = new DataTable();
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// Save a binary file to disk.
        /// </summary>
        /// <param name="response">The response used to save the file</param>
        /// 将二进制文件保存到磁盘
        private static bool SaveBinaryFile(WebResponse response, string FileName)
        {
            bool Value = true;
            byte[] buffer = new byte[1024];

            try
            {
                if (File.Exists(FileName))
                    File.Delete(FileName);
                Stream outStream = System.IO.File.Create(FileName);
                Stream inStream = response.GetResponseStream();

                int l;
                do
                {
                    l = inStream.Read(buffer, 0, buffer.Length);
                    if (l > 0)
                        outStream.Write(buffer, 0, l);
                }
                while (l > 0);

                outStream.Close();
                inStream.Close();
            }
            catch
            {
                Value = false;
            }
            return Value;
        }
        /// <summary>
        /// 下载照片
        /// </summary>
        /// <param name="PageURL">照片页地址</param>
        /// <param name="FileName">照片名称</param>
        private void DownLoad(string PageURL, string FileName, string cookieStr)
        {
            //访问照片页，找到下载地址
            string strResult = webRequest(PageURL, cookieStr);
            //下面分析文档结构
            //校内的程序员用JS加载，关键是取得大图的标记：p_large
            int FlagIndex = strResult.IndexOf("p_large");
            ///找得到的话，开始分析URL地址
            if (FlagIndex != 1)
            {
                int startIndex = strResult.Substring(0, FlagIndex + 1).LastIndexOf(@"http:\/\/");
                int EndIndex = strResult.Substring(startIndex).IndexOf('"');
                string URLStr = "";
                URLStr += strResult.Substring(startIndex, EndIndex);
                string RealPicUrl = URLStr.Replace(@"\/", @"/");

                //得到正确的地址后将照片下载到本地
                WebResponse response = null;
                Stream stream = null;
                //构造照片名称
                FileName += Path.GetExtension(RealPicUrl);
                try
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(RealPicUrl);
                    request.Method = "GET";
                    //request.CookieContainer = myCookie;
                    response = request.GetResponse();
                    stream = response.GetResponseStream();
                    if (!response.ContentType.ToLower().StartsWith("text/"))
                    {
                        SaveBinaryFile(response, FileName);
                    }
                }
                catch (Exception err)
                {
                }
            }
        }
        /// <summary>
        /// 进行后台作业
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            ThreadParam objParam = (ThreadParam)e.Argument;
            HtmlDocument dom = objParam.dom;
            //string folderName = "无标题";//GetAlbumTitle(dom.Body.ToString()) + @"\";
            string folderName = @"\" + GetAlbumTitle(objParam.domStr) + @"\";
            System.IO.Directory.CreateDirectory(DownloadPath + folderName);
            string Cookie = dom.Cookie;
            int albumPicCount = 0;
            int countStrIndex = objParam.domStr.IndexOf("<div class=\"float-left number-photo\">");
            int CountStrEndIndex = objParam.domStr.IndexOf("张", countStrIndex);
            string picCountStr = objParam.domStr.Substring(countStrIndex, CountStrEndIndex - countStrIndex);
            try
            {
                picCountStr = picCountStr.Substring(picCountStr.IndexOf("共"));
                picCountStr = picCountStr.Replace("共", "").Replace("页", "");
                albumPicCount = int.Parse(picCountStr);
            }
            catch { }
            if (!objParam.domStr.Contains("下一页</a></li>"))
            {
                try
                {
                    ///如果不存在下一页按钮，说明本相册只有一页
                    albumPageDownload(objParam.URL, 1, Cookie, folderName, albumPicCount);
                }
                catch { return; }
            }
            ///另一种判断方法，albumpiccount的判断方法并不一定准确，先使用上面的判断方法
            //if (albumPicCount < 16)
            //{
            //    ///如果总图片数小于16
            //    albumPageDownload(dom.Url.ToString(), 1, Cookie, folderName);
            //}
            HtmlElementCollection PicPageCollection = dom.GetElementById("opi").FirstChild.FirstChild.FirstChild.FirstChild.Children[2].Children[2].Children[1].FirstChild.Children;//获得相册页面数目及地址
            for (int i = 0; i < PicPageCollection.Count - 1; i++)
            {
                string albumPageURL = PicPageCollection[i].FirstChild.GetAttribute("href");
                albumPageDownload(albumPageURL, i + 1, Cookie, folderName, albumPicCount);
            }

        }
        /// <summary>
        /// 根据传递来的相册的某页进行下载
        /// </summary>
        /// <param name="PageURL">相册页的地址</param>
        /// <param name="pageIndex">在对相片进行命名时使用</param>
        /// <param name="Cookie">Cookie</param>
        private void albumPageDownload(string PageURL, int pageIndex, string Cookie, string folderName, int albumPicCount)
        {
            string strResult = webRequest(PageURL, Cookie);
            //校内的垃圾程序员，做出的页面不符合XHTML要求，用XML分析太过麻烦，下面依旧使用字符串分析法
            int pageUlStart = strResult.IndexOf("<div id=\"\" class=\"photo-list clearfix\">");
            int pageUlEnd = strResult.IndexOf(@"</div>", pageUlStart);
            if (pageUlStart == -1 || pageUlEnd == -1)
            {
                //解析不出来，下载失败
                return;
            }
            XmlDocument dom = new XmlDocument();
            dom.XmlResolver = null;
            strResult = strResult.Substring(pageUlStart, pageUlEnd - pageUlStart).Replace("?curpage=" + (pageIndex - 1).ToString() + "&t=", "").Replace("&t=", "") + "</div>";
            dom.LoadXml(strResult);
            XmlNodeList imgliColl = dom.FirstChild.FirstChild.ChildNodes;
            //getDom.DocumentText = strResult;            
            //HtmlElementCollection imgliColl = dom.GetElementById("content").Children[2].Children[3].FirstChild.Children;
            for (int i = 0; i < imgliColl.Count; i++)
            {
                string asd = imgliColl[i].FirstChild.FirstChild.Attributes[0].Name;
                string imgUrl = imgliColl[i].FirstChild.FirstChild.Attributes["href"].Value;    //GetAttribute("href");
                DownLoad(imgUrl, DownloadPath + folderName + ((pageIndex - 1) * 16 + i + 1).ToString(), Cookie);
                if (imgliColl.Count != 0)
                {
                    backgroundWorker1.ReportProgress((i * 100) / imgliColl.Count);
                }
            }

        }
        /// <summary>
        /// 封装的web请求类
        /// </summary>
        /// <param name="url"></param>
        /// <param name="cookie"></param>
        /// <returns>获得的页面源码</returns>
        private string webRequest(string url, string cookie)
        {
            HttpWebRequest hreq = (HttpWebRequest)HttpWebRequest.Create(url);
            hreq.Method = "GET";
            hreq.ContentType = "application/x-www-form-urlencoded";
            //自己创建的CookieContainer
            hreq.CookieContainer = GetCookieContainer(cookie);
            HttpWebResponse hres = (HttpWebResponse)hreq.GetResponse();
            //得到数据流
            Stream streamReceive = hres.GetResponseStream();
            //对获取到的数据流进行编码解析，让我们可以进行正常读取
            Encoding encoding = Encoding.UTF8;
            StreamReader streamReader = new StreamReader(streamReceive, encoding);
            //读取出数据流中的信息
            string strResult = streamReader.ReadToEnd();
            //关闭流
            streamReader.Close();
            //关闭网络响应流
            hres.Close();
            //返回结果
            return strResult;
        }
        /// <summary>
        /// 获得Cookie
        /// </summary>
        /// <param name="cookieStr">Cookie 字符串</param>
        private CookieContainer GetCookieContainer(string cookieStr)
        {
            CookieContainer myCookie = new CookieContainer();
            //string cookieStr = webBrowser1.Document.Cookie;
            string[] cookstr = cookieStr.Split(';');
            foreach (string str in cookstr)
            {
                string[] cookieNameValue = str.Split('=');
                Cookie ck = new Cookie(cookieNameValue[0].Trim().ToString(), cookieNameValue[1].Trim().ToString());
                ck.Domain = "www.renren.com";
                myCookie.Add(ck);
            }
            return myCookie;
        }
        /// <summary>
        /// 完成提醒
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            toolStripProgressBar1.Value = 0;
            MessageBox.Show("下载完成！");
        }
        /// <summary>
        /// 进度提示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            toolStripProgressBar1.Value = e.ProgressPercentage;
        }
        /// <summary>
        /// URL转向
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            Go2TbxURL();
        }
        /// <summary>
        /// 转向URL文本框中的地址
        /// </summary>
        private void Go2TbxURL()
        {
            string url = tbxURL.Text;
            if (!url.StartsWith(@"https://")) url = @"https://" + url;
            webBrowser1.Navigate(url);
        }
        /// <summary>
        /// 图片按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_MouseHover(object sender, EventArgs e)
        {
            pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
        }
        /// <summary>
        /// 自动转向
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbxURL_KeyDown(object sender, KeyEventArgs e)
        {
            ///按下Enter键发生
            if ((int)e.KeyCode == 13)
            {
                //e.SuppressKeyPress = true;
                Go2TbxURL();
            }
        }
        /// <summary>
        /// 设置存储地址
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox5_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.Description = "选择你要存放的路径！";
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                Config.Default.DownPath = folderBrowserDialog1.SelectedPath;
                Config.Default.Save();
                DownloadPath = Config.Default.DownPath;
            }
        }
        /// <summary>
        /// 下载图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox2_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                MessageBox.Show("请等待当前任务完成后添加新任务！");
                return;
            }
            if (DownloadPath == "")
            {
                MessageBox.Show("请先设置存放地址！");
                return;
            }
            if (!Directory.Exists(DownloadPath))
            {
                Directory.CreateDirectory(DownloadPath);
            }
            if (webBrowser1.Url.ToString().Contains("http://photo.renren.com/"))
            {
                ThreadParam newParam = new ThreadParam(webBrowser1.Document, webBrowser1.DocumentText, webBrowser1.Url.ToString());
                //启动后台线程
                backgroundWorker1.RunWorkerAsync(newParam);
                MessageBox.Show("启动成功！");
                toolStripStatusLabel3.Visible = true;
            }
            else MessageBox.Show("当前页面不是人人网相册页面！");
        }
        /// <summary>
        /// 取消任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripStatusLabel3_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
                MessageBox.Show("任务取消成功！");
                toolStripProgressBar1.Value = 0;
                toolStripStatusLabel3.Visible = false;
            }
        }
        /// <summary>
        /// 关于本软件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripStatusLabel2_Click(object sender, EventArgs e)
        {
            AboutBox1 aa = new AboutBox1();
            aa.ShowDialog();
        }

        private void panel1_Enter(object sender, EventArgs e)
        {

        }
        /// <summary>
        /// 获取相册标题
        /// </summary>
        /// <param name="Html"></param>
        /// <returns></returns>
        private string GetAlbumTitle(string Html)
        {
            int StartIndex = Html.IndexOf("<div class=\"Information\">");
            int EndIndex = Html.IndexOf("<p id=\"describeAlbum\" class=\"describe\">");
            if (StartIndex == -1 || EndIndex == -1)
            {
                return "无标题";
            }
            string subStr = Html.Substring(StartIndex, EndIndex - StartIndex);
            StartIndex = subStr.IndexOf("<h1>");
            EndIndex = subStr.IndexOf("</h1>");
            string albumTitle = subStr.Substring(StartIndex, EndIndex - StartIndex).Replace("<h1>", "");
            albumTitle = albumTitle.Replace(@"\", "").Replace(@"/", "").Replace(":", "").Replace("?", "").Replace("\"", "").Replace("|", "").Replace(">", "").Replace("<", "").Replace("", " ").Replace("    ", " ").Replace("  ", " ").Trim();
            //albumTitle = albumTitle.Replace("", " ").Replace("  ", " ");
            //文件夹名称过长的话，对之进行截断处理
            if (albumTitle.Length > 250)
            {
                albumTitle = albumTitle.Remove(250);
            }
            return albumTitle;
        }
        /// <summary>
        /// 强制在本窗口打开链接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser1_NewWindow(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            string url = this.webBrowser1.Document.ActiveElement.GetAttribute("href");
            this.webBrowser1.Navigate(url);
        }
        /// <summary>
        /// 同步地址栏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            tbxURL.Text = webBrowser1.Url.ToString();
        }
    }
}
/// <summary>
/// 不同线程之间传递参数使用
/// </summary>
public class ThreadParam
{
    public HtmlDocument dom;
    public string domStr;
    public string URL;
    public ThreadParam(HtmlDocument _dom, string _domStr, string _url)
    {
        dom = _dom;
        domStr = _domStr;
        URL = _url;
    }
}
